<template>
  <!-- 点位控制图 -->
  <div v-if="!isError" class="pointBox" ref="box">
    <!-- {{ pointList }} -->
    <!-- 背景 -->
    <a-spin :spinning="spinning" :tip="imgTip">
      <canvas ref="bargraphCanvas" :width="canvasHeight / canvasScale" :height="canvasHeight" :style="`top:0;left:0;z-index:1;width:${canvasHeight / canvasScale}px;height:${canvasHeight}px;`"></canvas>
    </a-spin>
    <!-- 点位 -->
    <canvas
      id="pointCanvas"
      ref="pointCanvas"
      :width="imgObject.width"
      :height="imgObject.height"
      :style="`position:absolute;z-index:2;width:${imgObject.width || 0}px;height:${imgObject.height || 0}px;left:${imgX}px;top:${imgY}px`"
    ></canvas>
    <!-- 下载背景图片 -->
    <div v-if="isTooltick || isDownload" :style="[overlayStyle]" style="position: absolute">
      <a-popover placement="left" :visible="visibleTooltick">
        <template slot="content">
          <slot :datas="record" />
          <!-- 下载背景图片 -->
          <a v-if="isDownload" style="margin: 5px" :href="img" target="_self">下载图片</a>
        </template>
      </a-popover>
    </div>
    <!-- 右键删除 -->
    <div v-if="isEdit" :style="[tooltipStyle]" style="position: absolute">
      <a-tooltip placement="right" :visible="visibleTooltick">
        <template slot="title">
          <span>右键删除</span>
        </template>
      </a-tooltip>
    </div>
    <!-- 其他操作 -->
    <div v-if="isTooltick || otherAction" :style="[overlayStyle]" style="position: absolute">
      <a-popover placement="left" :visible="visibleTooltick">
        <template slot="content">
          <a @click="handleAction">{{ otherAction }}</a>
        </template>
      </a-popover>
    </div>
  </div>
  <!-- 图片加载错误 -->
  <a-result v-else status="404" title="图片加载失败"></a-result>
</template>

<script>
import EXIF from 'exif-js'
import debounce from 'lodash/debounce'
import {mapGetters } from 'vuex'

export default {
  name: 'Points',
  props: {
    // 锚点的背景图
    img: {
      type: [Object, String],
      require: true
    },
    // 是否可编辑
    isEdit: {
      type: Boolean,
      default: () => false
    },
    // 初始化锚点列表
    pointer: {
      type: Array
    },
    // 最小缩放
    minScale: {
      type: [String, Number],
      default: () => 0.1
    },
    // 最大缩放
    maxScale: {
      type: [String, Number],
      default: () => 12
    },
    // 锚点颜色
    pointerColor: {
      type: String,
      default: () => '#1890ff'
    },
    // 选中锚点颜色
    pointerActiveColor: {
      type: String,
      default: () => '#ff4d4f'
    },
    // 序号字体颜色
    fontColor: {
      type: String,
      default: () => '#fff'
    },
    // 锚点半径
    circleRadius: {
      type: [String, Number],
      default: () => '14'
    },
    // 点位详情。双向绑定
    detail: Object,
    // 是否显示点位信息
    isTooltick: {
      type: Boolean,
      default: () => false
    },
    // 是否显示打点提示
    showMessage: {
      type: Boolean,
      default: () => false
    },
    // 图片加载提示
    imgTip: {
      type: String,
      default: () => '图片加载中'
    },
    // 是否支持下载背景图
    isDownload: {
      type: Boolean,
      default: () => false
    },
    // 其他操作行为
    otherAction: {
      type: String,
      default: () => '查看二维码'
    },
    // 是否需要导出点位图
    needPicture: {
      type: Boolean,
      default: () => false
    },
    // 是否压缩
    isCompress: {
      type: Boolean,
      default: () => true
    },
    // 限制打点数量
    limitPointNumber: Number
  },
  data() {
    this.init = debounce(this.init, 800)
    return {
      picture: '', // 点位图base64
      canvasWidth: 1500, // 画布宽度
      canvasHeight: 0, // 画布宽度
      isError: false, // 图片是否加载错误
      myCanvas: null, // 背景画布
      pointCanvas: null, // 锚点画布
      ctx: null, // 背景图层
      ctxPoint: null, // 锚点图层
      imgObject: {}, // 背景对象
      // pointList: [], // 锚点列表
      imgX: 50, // 图片在画布中渲染的起点x坐标
      imgY: 50, // 图片在画布中渲染的起点y坐标
      imgScale: 1, // 图片的缩放大小
      canvasScale: 1, // canvas长宽比
      overlayStyle: {}, // 气泡样式
      tooltipStyle: {}, // 气泡样式
      visibleTooltick: false, // 气泡显隐控件
      record: {}, // 点位详情
      boxWidth: 0, // 盒子宽度
      eventFlag: true, // 区别打点和拖拽点击的控件
      spinning: false // 图片加载状态
    }
  },
  mounted() {
    this.init()
    window.addEventListener('resize', this.init)
  },
  beforeDestroy() {
    window.removeEventListener('resize', this.init)
  },
  watch: {
    // 监听图片变化初始化
    img: {
      deep: true,
      handler() {
        this.init()
      }
    }
    // 监听点位列表回调
    // pointList: {
    //   deep: true,
    //   handler(e) {
    //     this.$emit('getPointer', e)
    //   }
    // }
  },
  computed: {
    ...mapGetters(['GET_DEVICE_PIXEL_RATIO']),
    // 默认光标
    defaultCursor() {
      return this.isEdit ? 'crosshair' : 'default'
    },
    // 锚点列表父子组件双向绑定
    pointList: {
      get: function () {
        return this.pointer || []
      },
      set: function (e) {
        this.$emit('update:pointer', e)
      }
    }
  },
  methods: {
    /**
     * @description: 悬浮框操作
     */
    handleAction() {
      this.$emit('remove', this.record)
      this.visibleTooltick = false
    },
    /**
     * @description: 生成图片
     * @param {String} w:画布宽度
     * @return {String} 图片base64编码
     */
    generatePic(w, fontSize) {
      let canvas = document.createElement('canvas') // 克隆画布
      let ctx = canvas.getContext('2d') // 画布2d对象
      let width = w || this.canvasHeight / this.canvasScale // 画布宽度
      let height = w ? w * this.canvasScale : this.canvasHeight // 画布高度
      // 设置画布尺寸
      canvas.width = width
      canvas.height = height
      // 画背景
      ctx.drawImage(
        this.imgObject.img, //规定要使用的图片
        0,
        0,
        width,
        height //要使用的图像的宽度、高度
      )
      // 描点
      this.drawPoint(ctx, width, height, false, fontSize)
      // 转成base64
      this.picture = canvas?.toDataURL('image/jpeg') || ''
    },
    /**
     * @description: 导出canvas整图
     * @param {String} name：导出文件名
     */
    exportCanvas(name) {
      // 生成图片
      this.generatePic(10000, 200)
      // 下载base64
      this.downloadFileByBase64(this.picture, name)
    },
    /**
     * @description: base64转文件Blob
     * @param {String} dataurl:base64的url
     * @return {Blob}
     */
    dataURLtoBlob(dataurl) {
      var arr = dataurl.split(','),
        mime = arr[0].match(/:(.*?);/)[1],
        bstr = atob(arr[1]),
        n = bstr.length,
        u8arr = new Uint8Array(n)
      while (n--) {
        u8arr[n] = bstr.charCodeAt(n)
      }
      // console.log(mime)
      return new Blob([u8arr], { type: mime })
    },
    /**
     * @description:
     * @param {String} url：文件链接
     * @param {String} name：文件名
     */
    downloadFile(url, name = 'canvas') {
      // console.log(name)
      var a = document.createElement('a')
      a.setAttribute('href', url)
      a.setAttribute('download', name + '.jpg')
      a.setAttribute('target', '_blank')
      let clickEvent = document.createEvent('MouseEvents')
      clickEvent.initEvent('click', true, true)
      a.dispatchEvent(clickEvent)
    },
    /**
     * @description:
     * @param {String} base64:base64
     * @param {String} name：文件名
     */
    downloadFileByBase64(base64, name) {
      var myBlob = this.dataURLtoBlob(base64) // base64转成blob
      var myUrl = URL.createObjectURL(myBlob) // 创建文件链接
      this.downloadFile(myUrl, name)
    },
    /**
     * @description: 组件初始化
     */
    init() {
      this.isError = false // 初始化，要不每次图片报错 this.$refs.bargraphCanvas undefined
      this.$nextTick(() => {
        if (this.img) {
          this.myCanvas = this.$refs.bargraphCanvas // 背景画布
          this.ctx = this.myCanvas.getContext('2d')
          this.boxWidth = this.$refs.box.getBoundingClientRect().width - 100
          this.canvasHeight = this.$refs.box.getBoundingClientRect().height // 画布背景高度
          // 初始化图片
          this.loadImg()
          // 初始化画布事件
          this.pointCanvas = this.$refs.pointCanvas // 锚点画布
          this.ctxPoint = this.pointCanvas.getContext('2d')
          this.canvasEventsInit()
        }
      })
    },
    /**
     * 根据图片拍摄方向还原图片正方向
     */
    compressImage(base64URL) {
      let _this = this
      return new Promise((resolve) => {
        // 若是网络图片
        if (base64URL.indexOf('http://') !== -1 || base64URL.indexOf('https://') !== -1 || base64URL.indexOf('www.') !== -1) {
          resolve(base64URL)
        }
        let orientation = ''
        let img = new Image()
        let canvas = document.createElement('canvas')
        let ctx = canvas.getContext('2d')
        img.src = base64URL
        _this.spinning = true
        img.onload = () => {
          // canvas对图片进行缩放
          canvas.width = img.width
          canvas.height = img.height
          // 清除画布
          ctx.clearRect(0, 0, canvas.width, canvas.height)
          // 根据图片拍摄方向还原图片正方向
          EXIF.getData(img, function () {
            orientation = EXIF.getTag(this, 'Orientation')
            // console.log(EXIF.getAllTags(this))
            switch (Number(orientation)) {
              case 2:
                ctx.translate(img.width, 0)
                ctx.scale(-1, 1)
                ctx.drawImage(img, 0, 0, img.width, img.height)
                break
              case 3:
                ctx.rotate((180 * Math.PI) / 180)
                ctx.drawImage(img, -img.width, -img.height, img.width, img.height)
                break
              case 4:
                ctx.translate(img.width, 0)
                ctx.scale(-1, 1)
                ctx.rotate((180 * Math.PI) / 180)
                ctx.drawImage(img, -img.width, -img.height, img.width, img.height)
                break
              case 5:
                ctx.translate(img.width, 0)
                ctx.scale(-1, 1)
                ctx.rotate((90 * Math.PI) / 180)
                ctx.drawImage(img, 0, -img.width, img.height, img.width)
                break
              case 6:
                canvas.width = img.height
                canvas.height = img.width
                ctx.rotate((-90 * Math.PI) / 180)
                ctx.drawImage(img, 0, 0, -img.width, img.height)
                break
              case 7:
                ctx.translate(img.width, 0)
                ctx.scale(-1, 1)
                ctx.rotate((270 * Math.PI) / 180)
                ctx.drawImage(img, -img.height, 0, img.height, img.width)
                break
              case 8:
                canvas.width = img.height
                canvas.height = img.width
                ctx.rotate((90 * Math.PI) / 180)
                ctx.drawImage(img, 0, 0, img.width, -img.height)
                // ctx.rotate((270 * Math.PI) / 180)
                // ctx.drawImage(img, -img.height, 0, img.height, img.width)
                break
              default:
                ctx.drawImage(img, 0, 0, img.width, img.height)
                break
            }
            let base64 = canvas.toDataURL('image/jpeg', 1)
            resolve(base64)
          })
        }
        img.onerror = (e) => {
          _this.isError = true
          _this.spinning = false
        }
      })
    },
    /**
     * 初始化图片
     */
    // loadImg() {
    async loadImg() {
      let _this = this
      if (_this.isCompress) {
        _this.imgObject = { url: await _this.compressImage(this.img), x: 0, y: 0, width: 1200, height: 700 }
      } else {
        _this.imgObject = { url: this.img, x: 0, y: 0, width: 1200, height: 700 }
      }
      //加载背景图片
      let img = new Image()
      let bgImg = _this.imgObject
      img.src = bgImg.url
      img.onload = function () {
        let boxWidth = _this.boxWidth // 盒子宽度
        let scale = boxWidth / img.width // 盒子和图片宽度比例
        _this.canvasScale = img.height / img.width // 图片长宽比
        let isFill = _this.canvasHeight / _this.canvasScale < boxWidth + 100 // 以图片最大高度计算宽度是否铺满画布
        let imgWidth = _this.canvasScale >= 1 || isFill ? (_this.canvasHeight - 100) / _this.canvasScale : boxWidth // 若图片长度大于宽度，则图片高度以图片宽度为参考
        let imgHeight = _this.canvasScale >= 1 || isFill ? _this.canvasHeight - 100 : img.height * scale // 若图片长度大于宽度，则图片高度以图片宽度为参考
        _this.imgObject = {
          img: img,
          x: bgImg.x,
          y: bgImg.y,
          width: imgWidth,
          height: imgHeight
        }
        _this.defaultImgObject = {
          img: img,
          x: bgImg.x,
          y: bgImg.y,
          width: imgWidth,
          height: imgHeight
        }
        // 重新计算图片初始化时的Y轴偏移值
        _this.imgY = (_this.canvasHeight - (_this.canvasScale >= 1 || isFill ? _this.canvasHeight - 100 : img.height * scale)) / 2
        // 若图片长度大于宽度
        if (_this.canvasScale >= 1 || isFill) {
          // 重新计算图片初始化时的X轴偏移值
          _this.imgX = (boxWidth + 100 - (_this.canvasHeight - 100) / _this.canvasScale) / 2
          //背景画布高度以图片宽度为参考
          _this.canvasHeight = (_this.boxWidth + 100) * _this.canvasScale
        }
        // 绘制背景图
        _this.$nextTick(_this.drawImage)
        // 若有默认锚点则加载
        if (_this.pointer?.length > 0) {
          _this.$nextTick(_this.drawPoint)
        }
        // 若需要导出
        if (_this.needPicture) {
          _this.$nextTick(() => {
            _this.generatePic(500)
          })
          _this.$nextTick(() => {
            _this.$emit('update:picture', _this.picture)
          })
        }
        _this.spinning = false
      }
      img.onerror = (e) => {
        _this.isError = true
        _this.spinning = false
      }
    },
    /**
     * @description: 绘制背景
     * @param {Object} ctx：canvas的2d对象
     * @param {Number} imgX：背景在画布上的x轴方向偏移值
     * @param {Number} imgY：背景在画布上的y轴方向偏移值
     * @param {Number} width：画布宽度
     * @param {Number} height：画布高度
     */
    drawImage() {
      let _this = this
      let imgObject = _this.imgObject
      _this.ctx.clearRect(0, 0, _this.canvasHeight / _this.canvasScale, _this.canvasHeight)
      _this.ctx.drawImage(
        imgObject.img, //规定要使用的图片
        this.imgX,
        this.imgY,
        imgObject.width,
        imgObject.height //要使用的图像的宽度、高度
      )
    },
    /**
     * @description: 绘制锚点
     * @param {Object} canvas：canvas的2d对象
     * @param {Number} width：画布宽度
     * @param {Number} height：画布高度
     * @param {Boolean} isClear：是否清除画布
     */
    drawPoint(canvas = this.ctxPoint, width = this.imgObject.width, height = this.imgObject.height, isClear = true, fontSize) {
      let _this = this
      let ctx = canvas
      let ctxWidth = width
      let ctxHeight = height
      isClear && ctx?.clearRect(0, 0, ctxWidth, ctxHeight)
      if (!ctx || !_this.pointList || _this.pointList?.length === 0) {
        return
      }
      // 遍历锚点
      _this.pointList.forEach((item, index) => {
        const actualType = item.actualType // actualType 0 公司 1 分公司 2 项目
        const actualStatus = item.actualStatus // actualStatus ：0未测量，1不合格，2合格
        let topCircle = item.isActive && isClear ? _this.pointerActiveColor : item.color || _this.pointerColor
        let bottomCircle = item.isActive && isClear ? _this.pointerActiveColor : item.color || _this.pointerColor
        let txtColor = item.fontColor || _this.fontColor
        if (actualStatus == '0') {
          topCircle = 'rgba(250, 250, 0, 1)'
          bottomCircle = 'rgba(250, 250, 0, 1)'
          txtColor = 'rgba(245, 154, 35, 1)'
        } else {
          if (actualType == '0') {
            topCircle = 'rgba(99, 0, 191, 1)'
          } else if (actualType == '1') {
            topCircle = 'rgba(245, 154, 35, 1)'
          } else if (actualType == '2') {
            topCircle = 'rgba(2, 167, 240, 1)'
          }
          if (actualStatus == '1') {
            bottomCircle = 'rgba(217, 0, 27, 1)'
          } else if (actualStatus == '2') {
            bottomCircle = 'rgba(112, 182, 3, 1)'
          }
        }
        // 开始绘制
        ctx.beginPath()
        // 绘制点
        ctx.arc(item.x * ctxWidth, item.y * ctxHeight, fontSize || Number(_this.circleRadius) + (item.isActive && isClear ? 4 : 0), Math.PI, 2 * Math.PI)
        // 编辑线条色；若有自己的颜色则使用，否则使用默认色
        ctx.strokeStyle = topCircle
        ctx.shadowBlur = 0
        ctx.stroke()
        // 绘制填充色；若有自己的颜色则使用，否则使用默认色
        ctx.fillStyle = topCircle
        // 填充背景
        ctx.fill()
        // 开始绘制
        ctx.beginPath()
        // 绘制点
        ctx.arc(item.x * ctxWidth, item.y * ctxHeight, fontSize || Number(_this.circleRadius) + (item.isActive && isClear ? 4 : 0), 0, Math.PI)
        // 编辑线条色；若有自己的颜色则使用，否则使用默认色
        ctx.strokeStyle = bottomCircle
        ctx.shadowBlur = 0
        ctx.stroke()
        // 绘制填充色；若有自己的颜色则使用，否则使用默认色
        ctx.fillStyle = bottomCircle
        // 填充背景
        ctx.fill()
        // 填充序号
        ctx.fillStyle = txtColor
        // 设置字体
        ctx.font = `${fontSize || (Number(_this.circleRadius) + (item.isActive && isClear ? 4 : 0)) * 1.3}px Georgia`
        // 设置字体水平居中
        ctx.textAlign = 'center'
        // 设置字体垂直居中
        ctx.textBaseline = 'middle'
        // 填充文字
        ctx.fillText(item.serialNumber || index + 1, item.x * ctxWidth, item.y * ctxHeight)
      })
    },
    /**
     * 判断当前坐标是否在锚点范围内,参数：事件event
     */
    whthinPoint(event) {
      let _this = this
      return new Promise((resolve, reject) => {
        for (let index in _this.pointList) {
          let item = _this.pointList[index]
          var xx = item.x * _this.imgObject.width - event.layerX / _this.GET_DEVICE_PIXEL_RATIO // 坐标点和锚点X轴差值
          var yy = item.y * _this.imgObject.height - event.layerY / _this.GET_DEVICE_PIXEL_RATIO // 坐标点和锚点Y轴差值
          var isMove = Math.sqrt(xx * xx + yy * yy) < _this.circleRadius // 求两点之间距离
          if (isMove) {
            resolve(item)
          }
        }
        reject(false)
      })
    },
    /**
     * 画布事件注册初始化
     */
    canvasEventsInit() {
      let _this = this
      let canvasList = [_this.myCanvas, _this.pointCanvas]
      // 遍历图层
      canvasList.forEach((canvas, index) => {
        // 鼠标点击过程事件注册
        _this.onmousedown(canvas)
        // 鼠标拖拽事件注册
        _this.move(canvas)
        // 若是锚点画布图层
        if (index == 1) {
          // canvas.style.cursor = _this.defaultCursor
          // 鼠标右键注册
          _this.oncontextmenu(canvas)
          // 鼠标点击注册
          _this.onclick(canvas)
        }
        // 滚轮事件注册
        _this.onwheel(canvas)
      })
    },
    /**
     * 点击事件注册
     */
    onclick(canvas) {
      let _this = this
      canvas.onclick = function (event) {
        if (_this.isDownload || _this.otherAction) {
          _this.visibleTooltick = false
        }
        _this
          .whthinPoint(event)
          .then((e) => {
            if (_this.eventFlag) {
              // 初始化锚点为未选中状态
              for (let item of _this.pointList) {
                item.isActive = false
              }
              // 将选中锚点添加选中状态
              e.isActive = true
              // 将选中锚点映射点位详情
              _this.record = e
              // 传出点位详情到父组件
              _this.$emit('update:detail', e)
              //重新绘制点图
              _this.drawPoint()
            }
          })
          .catch(() => {
            // 若是浏览状态
            // 若点位在边界内，可锚点
            if (
              _this.eventFlag &&
              // _this.isEdit &&
              event.offsetX / _this.GET_DEVICE_PIXEL_RATIO > _this.circleRadius &&
              _this.imgObject.width - event.offsetX / _this.GET_DEVICE_PIXEL_RATIO > _this.circleRadius &&
              event.offsetY / _this.GET_DEVICE_PIXEL_RATIO > _this.circleRadius &&
              _this.imgObject.height - event.offsetY / _this.GET_DEVICE_PIXEL_RATIO > _this.circleRadius
            ) {
              if (!_this.isEdit && _this.showMessage) {
                _this.$message.warning('请先添加测量点位类型！')
                return
              }
              let newPoint = {
                x: event.offsetX / _this.GET_DEVICE_PIXEL_RATIO / _this.imgObject.width,
                y: event.offsetY / _this.GET_DEVICE_PIXEL_RATIO / _this.imgObject.height
              }
              if (!_this.isEdit || _this.pointList.length >= _this.limitPointNumber) {
                return
              }
              _this.pointList.push(newPoint) // 添加新描点
              _this.$emit('getPointer', _this.pointList)
              _this.$emit('create', newPoint)
              _this.drawPoint() //重新绘制点图
            }
          })
      }
    },
    /**
     * 鼠标右键事件注册
     */
    oncontextmenu(canvas) {
      let _this = this
      canvas.oncontextmenu = function (event) {
        if (_this.isEdit) {
          _this
            .whthinPoint(event)
            .then((e) => {
              if (e.coordinate) {
                return
              }
              // 将选中锚点映射点位详情
              _this.record = e
              _this.visibleTooltick = false
              _this.pointList = _this.pointList.filter((i) => {
                // console.log(i.x !== e.x, i.y !== e.y)
                return i.x !== e.x || i.y !== e.y
              })
              _this.$nextTick(() => {
                // console.log(_this.pointList)
                _this.drawPoint()
                _this.$emit('getPointer', _this.pointList)
              })
              _this.$emit('remove', _this.record)
            })
            .catch(() => {})
        }
        if (_this.otherAction) {
          // 在点内才执行
          _this.whthinPoint(event).then((e) => {
            // console.log(e)
            // 将选中锚点映射点位详情
            _this.record = e
            _this.visibleTooltick = true
            // if (canvas.style.cursor != 'pointer') {
            _this.overlayStyle = {
              left: _this.imgX - _this.circleRadius + event.layerX / _this.GET_DEVICE_PIXEL_RATIO + 'px',
              top: _this.imgY - _this.circleRadius + event.layerY / _this.GET_DEVICE_PIXEL_RATIO + 'px'
            }
            // }
          })
        }
        if (_this.isDownload) {
          _this.visibleTooltick = true
          if (canvas.style.cursor != 'pointer') {
            _this.overlayStyle = {
              left: _this.imgX - _this.circleRadius + event.layerX / _this.GET_DEVICE_PIXEL_RATIO + 'px',
              top: _this.imgY - _this.circleRadius + event.layerY / _this.GET_DEVICE_PIXEL_RATIO + 'px'
            }
          }
        }
        return false
      }
    },
    /**
     * 滚轮事件注册
     */
    onwheel(canvas) {
      let _this = this
      canvas.onmousewheel = canvas.onwheel = function (event) {
        //滚轮放大缩小
        var wheelDelta = event.wheelDelta ? event.wheelDelta : event.deltalY * -40 //获取当前鼠标的滚动情况
        let defaultScale = _this.imgScale
        if (wheelDelta > 0) {
          _this.imgScale < _this.maxScale && (_this.imgScale *= 1.1) // 小于最大放大系数则放大
        } else {
          _this.imgScale > _this.minScale && (_this.imgScale *= 0.9) // 大于于最小缩小系数则缩小
        }
        let scale = (_this.imgScale / defaultScale).toFixed(2) // 相对缩放比例
        let isInner = event.toElement.id === 'pointCanvas' // 鼠标是否在图层内
        // 修改锚点定位
        if (isInner) {
          let parent = event.toElement // 鼠标的父级dom
          let Lx = event.offsetX / _this.GET_DEVICE_PIXEL_RATIO + parent.offsetLeft // 鼠标的父级dom的X
          let lx = event.offsetX / _this.GET_DEVICE_PIXEL_RATIO // 当前鼠标在图层内的X
          // let Ix = _this.imgX // 缩放前图层的X
          let x = Lx - lx * scale // 获取当前鼠标等比例缩放X
          let Ly = event.offsetY / _this.GET_DEVICE_PIXEL_RATIO + parent.offsetTop // 鼠标的父级dom的Y
          let ly = event.offsetY / _this.GET_DEVICE_PIXEL_RATIO // 当前鼠标在图层内的Y
          // let Iy = _this.imgY // 缩放前图层的Y
          let y = Ly - ly * scale // 获取当前鼠标等比例缩放Y
          // 映射图层坐标
          _this.imgX = x
          _this.imgY = y
        }
        _this.imgObject.width = _this.defaultImgObject.width * _this.imgScale.toFixed(2)
        _this.imgObject.height = _this.defaultImgObject.height * _this.imgScale.toFixed(2)
        _this.drawImage() //重新绘制图片
        _this.$nextTick(_this.drawPoint) //重新绘制锚点
        event.preventDefault && event.preventDefault()
        return false
      }
    },
    /**
     * 鼠标点击过程注册事件
     */
    onmousedown(canvas) {
      let _this = this
      canvas.onmousedown = function (event) {
        var imgx = _this.imgX
        var imgy = _this.imgY
        var pos = { x: event.clientX, y: event.clientY } //坐标转换，将窗口坐标转换成canvas的坐标
        canvas.onmousemove = function (evt) {
          setTimeout(function () {
            _this.eventFlag = false
          }, 100)
          //移动
          // console.log('move')
          canvas.style.cursor = 'move'
          var x = evt.clientX - pos.x + imgx
          var y = evt.clientY - pos.y + imgy
          _this.imgX = x
          _this.imgY = y
          _this.drawImage() //重新绘制图片
        }
        canvas.onmouseup = function () {
          setTimeout(function () {
            _this.eventFlag = true
          }, 200)
          canvas.onmouseup = null
          // canvas.style.cursor = _this.defaultCursor
          _this.move(canvas)
        }
      }
    },
    /**
     * 鼠标移动注册事件
     */
    move(canvas) {
      let _this = this
      canvas.onmousemove = function (evt) {
        // 若鼠标在点位内
        _this
          .whthinPoint(evt)
          .then((e) => {
            if (canvas.style.cursor != 'pointer') {
              if (_this.isTooltick || _this.isDownload) {
                _this.overlayStyle = {
                  left: _this.imgX - _this.circleRadius * 1.2 + evt.layerX / _this.GET_DEVICE_PIXEL_RATIO + 'px',
                  top: _this.imgY - _this.circleRadius + evt.layerY / _this.GET_DEVICE_PIXEL_RATIO + 'px'
                }
              }
              _this.tooltipStyle = {
                left: _this.imgX + _this.circleRadius * 1.2 + evt.layerX / _this.GET_DEVICE_PIXEL_RATIO + 'px',
                top: _this.imgY - _this.circleRadius + evt.layerY / _this.GET_DEVICE_PIXEL_RATIO + 'px'
              }
            }
            canvas.style.cursor = 'pointer'
            _this.record = e
            if (!e.coordinate) {
              _this.visibleTooltick = true
            }
          })
          .catch((err) => {
            // console.log(err)
            if (!_this.isDownload && !_this.otherAction) {
              _this.visibleTooltick = false
            }
            canvas.style.cursor = _this.defaultCursor
          })
      }
    }
  }
}
</script>

<style scoped>
.pointBox {
  height: 100%;
  overflow: hidden;
  background: #f3f3f3;
  position: relative;
}
</style>